Further workarounds for the broken string marshalling in xmlrpclib. Regardless
authoremellor@leeni.uk.xensource.com <emellor@leeni.uk.xensource.com>
Wed, 5 Apr 2006 23:59:06 +0000 (00:59 +0100)
committeremellor@leeni.uk.xensource.com <emellor@leeni.uk.xensource.com>
Wed, 5 Apr 2006 23:59:06 +0000 (00:59 +0100)
of the encoding used, one still may not include non-printable characters in an
XML document.  When a dmesg contains a ^D character, something seen on one of
our test machines, an invalid XML document is generated.

Use a trick by David Mertz to work around this -- escape the string using
Python's repr function.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
tools/python/xen/util/xmlrpclib2.py

index 65aa49ced53b99620ef3b685667560b085e15c83..0abc5d9149bb569c8c5d4bf4bb8d3d3b34e653a3 100644 (file)
@@ -20,6 +20,7 @@
 An enhanced XML-RPC client/server interface for Python.
 """
 
+import string
 import types
 
 from httplib import HTTPConnection, HTTP
@@ -54,6 +55,18 @@ class UnixTransport(Transport):
     def make_connection(self, host):
         return HTTPUnix(self.__handler)
 
+
+# See _marshalled_dispatch below.
+def conv_string(x):
+    if (isinstance(x, types.StringType) or
+        isinstance(x, unicode)):
+        s = string.replace(x, "'", r"\047")
+        exec "s = '" + s + "'"
+        return s
+    else:
+        return x
+
+
 class ServerProxy(xmlrpclib.ServerProxy):
     def __init__(self, uri, transport=None, encoding=None, verbose=0,
                  allow_none=1):
@@ -65,6 +78,16 @@ class ServerProxy(xmlrpclib.ServerProxy):
         xmlrpclib.ServerProxy.__init__(self, uri, transport, encoding,
                                        verbose, allow_none)
 
+
+    def __request(self, methodname, params):
+        response = xmlrpclib.ServerProxy.__request(self, methodname, params)
+
+        if isinstance(response, tuple):
+            return tuple([conv_string(x) for x in response])
+        else:
+            return conv_string(response)
+
+
 # This is a base XML-RPC server for TCP.  It sets allow_reuse_address to
 # true, and has an improved marshaller that logs and serializes exceptions.
 
@@ -79,14 +102,17 @@ class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
             else:
                 response = self._dispatch(method, params)
 
-            # Convert strings to unicode strings so that they are escaped
-            # properly by xmlrpclib.  We use latin-1 here, but any
-            # ASCII-compatible scheme would do -- we just care about getting
-            # the bytes across the wire.
-            # Any message handler that actually cares about the charset in
-            # use should be returning Unicode strings.
-            if isinstance(response, types.StringType):
-                response = unicode(response, 'iso-8859-1')
+            # With either Unicode or normal strings, we can only transmit
+            # \t, \n, \r, \u0020-\ud7ff, \ue000-\ufffd, and \u10000-\u10ffff
+            # in an XML document.  xmlrpclib does not escape these values
+            # properly, and then breaks when it comes to parse the document.
+            # To hack around this problem, we use repr here and exec above
+            # to transmit the string using Python encoding.
+            # Thanks to David Mertz <mertz@gnosis.cx> for the trick (buried
+            # in xml_pickle.py).
+            if (isinstance(response, types.StringType) or
+                isinstance(response, unicode)):
+                response = repr(response)[1:-1]
 
             response = (response,)
             response = xmlrpclib.dumps(response,